/**
 * Copyright 2008 Wink Saville
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Class AjaxMsgPipe
 */
function AjaxMsgPipe()
{
    debug("AjaxMsgPipe: E");
    this.pendingMsgs = new LinkList();
    this.requestSn = 0;
    this.responseSn = 0;
    this.receiverRequestSn = 0;
    this.sessionId = this.getAmpSessionId();
    this.receiver();
    this.startPendingMsgs();
    debug("AjaxMsgPipe: X");
} 

AjaxMsgPipe.prototype.getAmpSessionId = function() {
    debug("AjaxMsgPipe.getAmpSessionId: E");
    var req = new XMLHttpRequest();
    this.sessionId = -1;
    req.open("GET", "/ampSessionId", false);
    req.amp = this;
    req.setRequestHeader("Content-type", "application/text");
    req.send("");
    if (req.status != 200) {
        throw "AjaxMsgPipe.getAmpSessionId: error status=" + req.status;
    }
    debug("AjaxMsgPipe.getAmpSessionId: X rslt=" + req.responseText);
    return req.responseText;
}

AjaxMsgPipe.prototype.register = function(name) {
    debug("AjaxMsgPipe.register: E");
    var req = new XMLHttpRequest();
    req.open("POST", "/ampRegister", false);
    req.amp = this;
    
    req.setRequestHeader("Content-length", name.length);
    req.setRequestHeader("Content-type", "application/text");
    req.setRequestHeader("x-amp-id", this.sessionId);
    req.send(name);
    if (req.status != 200) {
        throw "AjaxMsgPipe.register: error status=" + req.status;
    }
    mcId = Deserializer.deserialize(req.responseText);
    
    debug("AjaxMsgPipe.register: X rslt=" + req.responseText);
    return mcId;
}

AjaxMsgPipe.prototype.lookup = function(name) {
    debug("AjaxMsgPipe.lookup: E");
    var req = new XMLHttpRequest();
    req.open("POST", "/ampLookup", false);
    req.amp = this;
    
    req.setRequestHeader("Content-length", name.length);
    req.setRequestHeader("Content-type", "application/text");
    req.setRequestHeader("x-amp-id", this.sessionId);
    req.send(name);
    if (req.status != 200) {
        throw "AjaxMsgPipe.lookup: error status=" + req.status;
    }
    
    /* Return the dstId or -1 if an error */
    debug("AjaxMsgPipe.lookup: X rslt='" + req.responseText + "'");
    return req.responseText < 0 ? -1 : req.responseText;
}

AjaxMsgPipe.prototype.sendSync = function (msg) {
    var req = new XMLHttpRequest();
    req.open("POST", "/ampSync", false);
    req.amp = this;
    var d = msg.toJSONString();
    req.setRequestHeader("Content-length", d.length);
    req.setRequestHeader("Content-type", "application/text");
    req.setRequestHeader("x-amp-id", this.sessionId);
    req.send(d);
    if (req.status != 200) {
        rsltMsg = null;
    } else {
    	rsltMsg = Deserializer.deserialize(rslt);
    }
    
    debug("AjaxMsgPipe.sendSync: rsltMsg='" + rsltMsg + "'");
    return rsltMsg;
}

AjaxMsgPipe.prototype.receiver = function () {
    //debug("AjaxMsgPipe.receiver: E");
    var req = new XMLHttpRequest();
    req.open("GET", "/amp", true);
    req.amp = this;
    req.onreadystatechange = function ()
    {
        var amp = req.amp;
        //debug("AjaxMsgPipe.receiver: readyState=" + req.readyState);
        if (req.readyState == 4) {       
            if (req.status == 200) {
                //debug("AjaxMsgPipe.receiver: E onreadystatechange OK");
                var rslt = req.responseText;
                var responseId = req.getResponseHeader("x-amp-id");
                var responseSn = req.getResponseHeader("x-amp-sn");

                //debug("AjaxMsgPipe.receiver: status=" + req.status + " responseId=" + responseId
                // + " responseSn=" + responseSn + " sessionId=" + amp.sessionId
                // + " requestSn=" + amp.receiverRequestSn);

                if (responseId != amp.sessionId) {
                    /* TODO: Do something less drastic */
                    debug("AjaxMsgPipe.receiver: error responseId("+responseId+") != requestId("+amp.sessionId+")");
                    throw "AjaxMsgPipe.receiver: error responseId("+responseId+") != requestSn("+amp.sessionId+")";
                }
                if (responseSn != amp.receiverRequestSn) {
                    /* TODO: Do something less drastic */
                    debug("AjaxMsgPipe.receiver: error responseSn("+responseSn+") != requestSn("+amp.receiverRequestSn+")");
                    throw "AjaxMsgPipe.receiver: error responseSn("+responseSn+") != requestSn("+amp.receiverRequestSn+")";
                }
                
                /* All is well, forward this message */
            	var msg = Deserializer.deserialize(rslt);
            	McMgr.sendMsg(msg);
                	
                /* GET another message */
                amp.receiver();
                //debug("AjaxMsgPipe.receiver: onreadystatechange X after  call to amp.receiver()");
            } else {
                /*
                 * TODO: Bad problem, server is probably down we should
                 *       eventually add retry some where. For now we'll
                 *       just throw an error.
                 */
                debug("AjaxMsgPipe.receiver: readyState=4 error status=" + req.status);
                throw "AjaxMsgPipe.receiver: readyState=4 error status=" + req.status;
            }
        }
    }

    req.setRequestHeader("Content-type", "application/text");
    this.receiverRequestSn += 1;
    req.setRequestHeader("x-amp-id", this.sessionId);
    req.setRequestHeader("x-amp-sn", this.receiverRequestSn);
    req.send("");
    //debug("AjaxMsgPipe.receiver: X  sent x-amp-id="+this.sessionId+" x-amp-sn="+this.receiverRequestSn);
}

AjaxMsgPipe.prototype.sender = function (msg) {
    //debug("AjaxMsgPipe.sender: E");
    var req = new XMLHttpRequest();
    req.open("POST", "/amp", true);
    req.amp = this;
    req.onreadystatechange = function ()
    {
        var amp = req.amp;
        //debug("AjaxMsgPipe.sender: readyState=" + req.readyState);
        if (req.readyState == 4) {       
            if (req.status == 200) {
                //debug("AjaxMsgPipe.sender: E onreadystatechange OK");
                var rslt = req.responseText;
                var responseId = req.getResponseHeader("x-amp-id");
                var responseSn = req.getResponseHeader("x-amp-sn");

                //debug("AjaxMsgPipe.sender: status=" + req.status + " responseId=" + responseId
                // + " responseSn=" + responseSn + " sessionId=" + amp.sessionId
                // + " requestSn=" + amp.requestSn);

                if (responseId != amp.sessionId) {
                    /* TODO: Do something less drastic */
                    debug("AjaxMsgPipe.sender: error responseId("+responseId+") != requestId("+amp.sessionId+")");
                    throw "AjaxMsgPipe.sender: error responseId("+responseId+") != requestSn("+amp.sessionId+")";
                }
                if (responseSn != amp.requestSn) {
                    /* TODO: Do something less drastic */
                    debug("AjaxMsgPipe.sender: error responseSn("+responseSn+") != requestSn("+amp.requestSn+")");
                    throw "AjaxMsgPipe.sender: error responseSn("+responseSn+") != requestSn("+amp.requestSn+")";
                }

                amp.startPendingMsgs();
                amp.responseSn += 1;
                //debug("AjaxMsgPipe.sender: onreadystatechange X");
            } else {
                /* TODO: We should probably resend the message a limited number of times? */
                debug("AjaxMsgPipe.sender: readyState=4 error status=" + req.status);
                throw "AjaxMsgPipe.sender: readyState=4 error status=" + req.status;
            }
        }
    }

    var d = msg.toJSONString();
    req.setRequestHeader("Content-length", d.length);
    req.setRequestHeader("Content-type", "application/text");
    this.requestSn += 1;
    req.setRequestHeader("x-amp-id", this.sessionId);
    req.setRequestHeader("x-amp-sn", this.requestSn);
    req.send(d);
    //debug("AjaxMsgPipe.sender: X  sent requestSn="+this.requestSn+" d='"+d+"'");
}

AjaxMsgPipe.prototype.startPendingMsgs = function () {
    var msg = this.pendingMsgs.pop();
    if (msg != null) {
        this.sender(msg);
    } else {
        //debug("AjaxMsgPipe: startPendinMsgs; no pending");
    }
}

AjaxMsgPipe.prototype.forwardMsg = function (msg) {
    if (this.requestSn == this.responseSn) {
        //debug("AjaxMsgPipe.sendMsg: sending responseSn=" + this.responseSn + " requestSn=" + this.requestSn);
        this.sender(msg);
    } else {
        //debug("AjaxMsgPipe.sendMsg: pending responseSn=" + this.responseSn + " requestSn=" + this.requestSn);
        this.pendingMsgs.append(msg);
    }
}
